/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.service.impl;

import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.common.core.utils.file.FileUtils;
import com.comac.ins.common.excel.utils.ExcelUtil;
import com.comac.ins.common.json.utils.JsonUtils;
import com.comac.ins.common.mybatis.core.page.PageQuery;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.isfd.constant.IsfdMeshModelConstants;
import com.comac.ins.isfd.constant.MongoDataConstant;
import com.comac.ins.isfd.constant.enums.*;
import com.comac.ins.isfd.domain.IsfdDatabaseMongoQuery;
import com.comac.ins.isfd.domain.IsfdMeshCompareResult;
import com.comac.ins.isfd.domain.IsfdMeshCompareTask;
import com.comac.ins.isfd.domain.bo.IsfdMeshCompareQueryBo;
import com.comac.ins.isfd.domain.vo.IsfdMeshCompareResultFileVo;
import com.comac.ins.isfd.service.IIsfdDatabaseMongoService;
import com.comac.ins.isfd.service.IIsfdMeshCompareService;
import com.comac.ins.isfd.util.CardUtils;
import com.comac.ins.isfd.util.bdfparser.entities.bdf.rawdata.RawDataLine;
import com.comac.ins.isfd.util.bdfparser.entities.comparator.BDFCompareResult;
import com.comac.ins.isfd.util.bdfparser.output.BDFComparators;
import com.comac.ins.system.service.ISysDictDataService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * 自然网格模型对比service业务处理
 *
 * @author lj
 * @date 2025-01-13
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class IsfdMeshCompareServiceImpl implements IIsfdMeshCompareService {

    @Autowired
    private IIsfdDatabaseMongoService mongoService;

    @Autowired
    private ISysDictDataService iSysDictDataService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean createCompareTask(IsfdMeshCompareTask task) {
        String collectionName = MongoDataConstant.MESH_COMPARE_TASK_TABLE_NAME;
        task.setStatus(IsfdMeshCompareTaskStatusEnum.IN_PROGRESS.getValue());
        try {
            task.setType(IsfdMeshCompareTaskTypeEnum.valueOf(task.getType().toUpperCase()).getValue());
        } catch (Exception e) {
            log.error("不是支持的type！" + e);
            throw new BaseException("不是支持的type！");
        }
        // 验证文件是否存在
        Path comparedFilePath = Paths.get(task.getComparedObject().getFilePath());
        Path referencedFilePath = Paths.get(task.getReferencedObject().getFilePath());
        String comparedFileExtension = FileUtils.getFileExtension(comparedFilePath);
        String referencedFileExtension = FileUtils.getFileExtension(referencedFilePath);
        if (!IsfdModelMeshFileSuffixEnum.isBdf(comparedFileExtension) || !IsfdModelMeshFileSuffixEnum.isBdf(referencedFileExtension)) {
            throw new BaseException("对比文件或者参照文件的格式不正确，请确认后重试!");
        }
        if (!Files.exists(comparedFilePath) || !Files.exists(referencedFilePath)) {
            throw new BaseException("无法创建任务，文件不存在!");
        }
        if (comparedFilePath.toString().toLowerCase().contains(IsfdMeshModelConstants.MODEL_MESH_P_LOAD_IGNORE_CASE) ||
            referencedFilePath.toString().toLowerCase().contains(IsfdMeshModelConstants.MODEL_MESH_P_LOAD_IGNORE_CASE)) {
            throw new BaseException("PLoad文件暂时不能进行对比，请确认后重试!");
        }

        task.setCreateTime(new Date());
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> data = objectMapper.convertValue(task, new TypeReference<>() {
        });
        // 保存任务状态
        String taskIdStr = mongoService.save(collectionName, data);
        if (StringUtils.isNotBlank(taskIdStr)) {
            // 提交异步任务
            CompletableFuture.runAsync(() -> saveCompareResult(task, taskIdStr));
            return true;
        }
        return false;
    }

    @Override
    public void saveCompareResult(IsfdMeshCompareTask task, String taskIdStr) {
        try {
            String collectionName = MongoDataConstant.MESH_COMPARE_RESULT_TABLE_NAME;
            // 构造结果基本信息数据
            IsfdMeshCompareResult compareResult = new IsfdMeshCompareResult();
            compareResult.set_id(taskIdStr);
            compareResult.setType(task.getType());
            compareResult.setComparedObject(task.getComparedObject());
            compareResult.setReferencedObject(task.getReferencedObject());
            ObjectMapper objectMapper = new ObjectMapper();
            Map<String, Object> data = objectMapper.convertValue(compareResult, new TypeReference<>() {
            });
            // 保存结果数据的基本信息数据
            mongoService.save(collectionName, data);
            // 开始对比
            Path compareFile = Paths.get(task.getComparedObject().getFilePath());
            Path referenceFile = Paths.get(task.getReferencedObject().getFilePath());
            BDFCompareResult result = BDFComparators.compareBDFFiles(compareFile, referenceFile);
            // 把结果文件写入本地
            writeResultToExcel(compareResult, result);
            Map<String, Object> containsUrlData = objectMapper.convertValue(compareResult, new TypeReference<>() {
            });
            mongoService.updateById(collectionName, taskIdStr, containsUrlData);

            // 更新任务状态为完成
            updateTaskStatus(taskIdStr, IsfdMeshCompareTaskStatusEnum.COMPLETED, "");
        } catch (Exception e) {
            log.error("保存对比文件失败", e);
            String message = e.getMessage();
            updateTaskStatus(taskIdStr, IsfdMeshCompareTaskStatusEnum.FAILED, message);
        }
    }

    public void updateTaskStatus(String taskId, IsfdMeshCompareTaskStatusEnum status, String message) {
        String collectionName = MongoDataConstant.MESH_COMPARE_TASK_TABLE_NAME;
        Map<String, Object> update = new HashMap<>();
        update.put("status", status.getValue());
        if (StringUtils.isNotBlank(message)) {
            update.put("message", message.length() >= 255 ? message.substring(0, 255) : message);
        }
        mongoService.updateById(collectionName, taskId, update);
    }

    @Override
    public TableDataInfo<Document> queryList(IsfdMeshCompareQueryBo queryBo) {
        String type = queryBo.getType();
        String modelNumber = queryBo.getModelNumber();
        String sectionNumber = queryBo.getSectionNumber();
        PageQuery pageQuery = queryBo.getPageQuery();

        List<IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition> conditions = new ArrayList<>();
        if (StringUtils.isNotBlank(type) && StringUtils.isBlank(modelNumber) && StringUtils.isBlank(sectionNumber)) {
            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationType = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationType.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationType.setValue(type);
            operationType.setFieldName("type");
            conditions.add(operationType);
        }

        if (StringUtils.isNotBlank(type) && StringUtils.isNotBlank(modelNumber) && StringUtils.isBlank(sectionNumber)) {
            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationType = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationType.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationType.setValue(type);
            operationType.setFieldName("type");
            conditions.add(operationType);

            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationModel1 = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationModel1.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationModel1.setValue(modelNumber);
            operationModel1.setFieldName("referencedObject.modelNumber");
            operationModel1.setLogicalOperator(IsfdMongoQueryLogicalOperatorEnum.OR.getValue());
            conditions.add(operationModel1);

            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationModel2 = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationModel2.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationModel2.setValue(modelNumber);
            operationModel2.setFieldName("comparedObject.modelNumber");
            operationModel2.setLogicalOperator(IsfdMongoQueryLogicalOperatorEnum.OR.getValue());
            conditions.add(operationModel2);
        }

        if (StringUtils.isNotBlank(type) && StringUtils.isNotBlank(modelNumber) && StringUtils.isNotBlank(sectionNumber)) {
            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationType = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationType.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationType.setValue(type);
            operationType.setFieldName("type");
            conditions.add(operationType);

            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationModel1 = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationModel1.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationModel1.setValue(modelNumber);
            operationModel1.setFieldName("referencedObject.modelNumber");
            conditions.add(operationModel1);

            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationSection1 = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationSection1.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationSection1.setValue(sectionNumber);
            operationSection1.setFieldName("referencedObject.sectionNumber");
            conditions.add(operationSection1);

            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationModel2 = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationModel2.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationModel2.setValue(modelNumber);
            operationModel2.setFieldName("comparedObject.modelNumber");
            operationModel2.setLogicalOperator(IsfdMongoQueryLogicalOperatorEnum.OR.getValue());
            conditions.add(operationModel2);

            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationSection2 = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationSection2.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationSection2.setValue(sectionNumber);
            operationSection2.setFieldName("comparedObject.sectionNumber");
            operationSection2.setLogicalOperator(IsfdMongoQueryLogicalOperatorEnum.OR.getValue());
            conditions.add(operationSection2);
        }

        if (StringUtils.isBlank(type) && StringUtils.isNotBlank(modelNumber) && StringUtils.isBlank(sectionNumber)) {
            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationModel1 = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationModel1.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationModel1.setValue(modelNumber);
            operationModel1.setFieldName("referencedObject.modelNumber");
            operationModel1.setLogicalOperator(IsfdMongoQueryLogicalOperatorEnum.OR.getValue());
            conditions.add(operationModel1);

            IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition operationModel2 = new IsfdDatabaseMongoQuery.IsfdDatabaseMongoQueryCondition();
            operationModel2.setOperator(IsfdMongoQueryOperatorEnum.EQUAL.getValue());
            operationModel2.setValue(modelNumber);
            operationModel2.setFieldName("comparedObject.modelNumber");
            operationModel2.setLogicalOperator(IsfdMongoQueryLogicalOperatorEnum.OR.getValue());
            conditions.add(operationModel2);
        }

        IsfdDatabaseMongoQuery queryCondition = new IsfdDatabaseMongoQuery();
        queryCondition.setConditions(conditions);
        queryCondition.setPageQuery(pageQuery);

        String collectionName = MongoDataConstant.MESH_COMPARE_TASK_TABLE_NAME;
        // 查询结果
        Long totalCount = mongoService.count(collectionName, queryCondition);
        List<Document> documents = mongoService.aggregationQuery(collectionName, queryCondition);
        return TableDataInfo.build(documents, totalCount);
    }

    @Override
    public Document queryResultDetail(String objectId) {
        String collectionName = MongoDataConstant.MESH_COMPARE_RESULT_TABLE_NAME;
        // 查询结果
        return mongoService.findById(collectionName, objectId);
    }

    @Override
    public Boolean deleteCompareTask(String objectId) {
        String taskCollectionName = MongoDataConstant.MESH_COMPARE_TASK_TABLE_NAME;
        String resultCollectionName = MongoDataConstant.MESH_COMPARE_RESULT_TABLE_NAME;
        mongoService.deleteByIds(taskCollectionName, Collections.singletonList(objectId));
        mongoService.deleteByIds(resultCollectionName, Collections.singletonList(objectId));
        return true;
    }

    @Override
    public void report(String id, HttpServletResponse response) {
        Document document = mongoService.findById(MongoDataConstant.MESH_COMPARE_RESULT_TABLE_NAME, id);
        if (document == null) {
            throw new BaseException("未找到文件！");
        }
        Path filePath = Paths.get(document.getString("compareResultFileUrl"));
        // 确保文件存在
        if (!Files.exists(filePath)) {
            throw new BaseException("未找到文件！");
        }

        FileUtils.setAttachmentResponseHeader(response, filePath.getFileName().toString());
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");

        // 写入文件内容到响应
        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(filePath.toFile()))) {
            IOUtils.copy(in, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            log.error("写出文件报错", e);
            throw new BaseException("写出文件报错");
        }
    }

    @Override
    public String base64Report(String id) {
        Document document = mongoService.findById(MongoDataConstant.MESH_COMPARE_RESULT_TABLE_NAME, id);
        if (document == null) {
            throw new BaseException("未找到文件！");
        }
        Path filePath = Paths.get(document.getString("compareResultFileUrl"));
        // 确保文件存在
        if (!Files.exists(filePath)) {
            throw new BaseException("未找到文件！");
        }
        byte[] fileBytes;
        try {
            fileBytes = Files.readAllBytes(filePath);
        } catch (Exception e) {
            log.error("读取文件时发生错误!", e);
            throw new BaseException("读取文件时发生错误！");
        }
        return Base64.getEncoder().encodeToString(fileBytes);
    }

    private void writeResultToExcel(IsfdMeshCompareResult isfdMeshCompareResult, BDFCompareResult result) {
        List<RawDataLine> addedCards = result.getAddedCards();
        // 这里的add 还是remove根据业务方的邀请而定
        List<IsfdMeshCompareResultFileVo> addData = new ArrayList<>();
        if (!CollectionUtils.isEmpty(addedCards)) {
            for (RawDataLine rawDataLine : addedCards) {
                IsfdMeshCompareResultFileVo add = new IsfdMeshCompareResultFileVo();
                add.setCardName(CardUtils.getCardName(rawDataLine.getLine()));
                add.setComparerResultType(IsfdMeshCompareResultTypeEnum.REMOVE.getDesc());
                add.setReferencedContent(rawDataLine.getLine());
                add.setReferencedLine((long) rawDataLine.getRowNumber());
                add.setReferencedFileName(rawDataLine.getRelativePath());
                addData.add(add);
            }
        }
        List<RawDataLine> removedCards = result.getRemovedCards();
        List<IsfdMeshCompareResultFileVo> removeData = new ArrayList<>();
        if (!CollectionUtils.isEmpty(removedCards)) {
            for (RawDataLine rawDataLine : removedCards) {
                IsfdMeshCompareResultFileVo remove = new IsfdMeshCompareResultFileVo();
                remove.setCardName(CardUtils.getCardName(rawDataLine.getLine()));
                remove.setComparerResultType(IsfdMeshCompareResultTypeEnum.ADD.getDesc());
                remove.setComparedContent(rawDataLine.getLine());
                remove.setComparedLine((long) rawDataLine.getRowNumber());
                remove.setComparedFileName(rawDataLine.getRelativePath());
                removeData.add(remove);
            }
        }
        List<BDFCompareResult.ModifiedCard> modifiedCards = result.getModifiedCards();
        List<IsfdMeshCompareResultFileVo> modifiedData = new ArrayList<>();
        if (!CollectionUtils.isEmpty(modifiedCards)) {
            for (BDFCompareResult.ModifiedCard modifiedCard : modifiedCards) {
                List<RawDataLine> oldRawDataLines = modifiedCard.getOldRawDataLine();
                List<RawDataLine> newRawDataLines = modifiedCard.getNewRawDataLine();
                int maxSize = Math.max(oldRawDataLines.size(), newRawDataLines.size());
                for (int i = 0; i < maxSize; i++) {
                    IsfdMeshCompareResultFileVo modified = new IsfdMeshCompareResultFileVo();
                    modified.setComparerResultType(IsfdMeshCompareResultTypeEnum.MODIFIED.getDesc());
                    RawDataLine oldLine = i < oldRawDataLines.size() ? oldRawDataLines.get(i) : null;
                    RawDataLine newLine = i < newRawDataLines.size() ? newRawDataLines.get(i) : null;
                    if (oldLine != null) {
                        if (StringUtils.isBlank(modified.getCardName())) {
                            modified.setCardName(CardUtils.getCardName(oldLine.getLine()));
                        }
                        modified.setComparedContent(oldLine.getLine());
                        modified.setComparedLine((long) oldLine.getRowNumber());
                        modified.setComparedFileName(oldLine.getRelativePath());
                    }
                    if (newLine != null) {
                        if (StringUtils.isBlank(modified.getCardName())) {
                            modified.setCardName(CardUtils.getCardName(newLine.getLine()));
                        }
                        modified.setReferencedContent(newLine.getLine());
                        modified.setReferencedLine((long) newLine.getRowNumber());
                        modified.setReferencedFileName(newLine.getRelativePath());
                    }
                    modifiedData.add(modified);
                }
            }
        }

        String prefixPath = iSysDictDataService.selectDictValueByTypeAndLabel(IsfdMeshModelConstants.MODEL_MESH, IsfdMeshModelConstants.MODEL_MESH_DATA_PREFIX);
        if (StringUtils.isBlank(prefixPath)) {
            throw new BaseException("自然网格模型库上传地址前缀未配置，请到字典菜单栏配置该项。");
        }

        // 原始文件写入
        Map<String, Object> data = new HashMap<>();
        data.put(IsfdMeshCompareResultTypeEnum.REMOVE.getDesc(), addData);
        data.put(IsfdMeshCompareResultTypeEnum.ADD.getDesc(), removeData);
        data.put(IsfdMeshCompareResultTypeEnum.MODIFIED.getDesc(), modifiedData);
        String compareResultFileUrl = prefixPath + IsfdMeshModelConstants.MODEL_MESH_DATA_COMPARE_DIR + isfdMeshCompareResult.get_id() + ".xlsx";
        ExcelUtil.writeDataToExcel(data, IsfdMeshCompareResultFileVo.class, compareResultFileUrl);

        // 写入新文件，处理有 + 的文件写入，合并到一行
        Map<String, Object> dataMergePlus = new HashMap<>();
        // 处理 addData
        List<IsfdMeshCompareResultFileVo> addDataMergePlus = new ArrayList<>();
        String lineSeparator = System.lineSeparator();
        for (int i = 0; i < addData.size(); i++) {
            IsfdMeshCompareResultFileVo current = addData.get(i);
            if (i > 0) {
                IsfdMeshCompareResultFileVo previous = addDataMergePlus.get(addDataMergePlus.size() - 1);
                if (previous.getReferencedContent().trim().endsWith("+") && current.getReferencedContent().trim().startsWith("+")) {
                    // 合并 comparedContent
                    previous.setReferencedContent(previous.getReferencedContent() + lineSeparator + current.getReferencedContent());
                    continue; // 跳过当前对象，不添加到 addDataMergePlus
                }
            }
            addDataMergePlus.add(current);
        }

        // 处理 removeData
        List<IsfdMeshCompareResultFileVo> removeDataMergePlus = new ArrayList<>();
        for (int i = 0; i < removeData.size(); i++) {
            IsfdMeshCompareResultFileVo current = removeData.get(i);
            if (i > 0) {
                IsfdMeshCompareResultFileVo previous = removeDataMergePlus.get(removeDataMergePlus.size() - 1);
                if (previous.getComparedContent().trim().endsWith("+") && current.getComparedContent().trim().startsWith("+")) {
                    // 合并 referencedContent
                    previous.setComparedContent(previous.getComparedContent() + lineSeparator + current.getComparedContent());
                    continue; // 跳过当前对象，不添加到 removeDataMergePlus
                }
            }
            removeDataMergePlus.add(current);
        }

        // 处理 modifiedData
        List<IsfdMeshCompareResultFileVo> modifiedDataMergePlus = new ArrayList<>();
        for (int i = 0; i < modifiedData.size(); i++) {
            Boolean needAdd = Boolean.TRUE;
            IsfdMeshCompareResultFileVo current = modifiedData.get(i);
            if (i > 0) {
                IsfdMeshCompareResultFileVo previous = modifiedDataMergePlus.get(modifiedDataMergePlus.size() - 1);
                try {
                    if (StringUtils.isNotBlank(previous.getComparedContent())) {
                        if (previous.getComparedContent().trim().endsWith("+") && current.getComparedContent().trim().startsWith("+")) {
                            // 合并 comparedContent
                            previous.setComparedContent(previous.getComparedContent() + lineSeparator + current.getComparedContent());
                            needAdd = Boolean.FALSE;
                        }
                    }
                    if (StringUtils.isNotBlank(previous.getReferencedContent())) {
                        // 如果 referencedContent 也需要合并
                        if (previous.getReferencedContent().trim().endsWith("+") && current.getReferencedContent().trim().startsWith("+")) {
                            previous.setReferencedContent(previous.getReferencedContent() + lineSeparator + current.getReferencedContent());
                            needAdd = Boolean.FALSE;
                        }
                    }
                } catch (Exception e) {
                    log.error("处理 modifiedData 失败，current is :{}，previous is {}", JsonUtils.toJsonString(current), JsonUtils.toJsonString(previous), e);
                    throw new BaseException(e.getMessage());
                }
            }
            if (needAdd) {
                modifiedDataMergePlus.add(current);
            }
        }
        dataMergePlus.put(IsfdMeshCompareResultTypeEnum.REMOVE.getDesc(), addDataMergePlus);
        dataMergePlus.put(IsfdMeshCompareResultTypeEnum.ADD.getDesc(), removeDataMergePlus);
        dataMergePlus.put(IsfdMeshCompareResultTypeEnum.MODIFIED.getDesc(), modifiedDataMergePlus);
        String compareResultFileUrlMergePlusPlus = prefixPath + IsfdMeshModelConstants.MODEL_MESH_DATA_COMPARE_DIR + isfdMeshCompareResult.get_id() + "_" + "MergePlus" + ".xlsx";
        ExcelUtil.writeDataToExcel(dataMergePlus, IsfdMeshCompareResultFileVo.class, compareResultFileUrlMergePlusPlus);

        isfdMeshCompareResult.setCompareResultOriginalFileUrl(compareResultFileUrl);
        isfdMeshCompareResult.setCompareResultFileUrl(compareResultFileUrlMergePlusPlus);
    }


    private void writeResultToExcel2(IsfdMeshCompareResult isfdMeshCompareResult, BDFCompareResult result) {
        List<RawDataLine> addedCards = result.getAddedCards();
        List<IsfdMeshCompareResultFileVo> addData = new ArrayList<>();
        if (!CollectionUtils.isEmpty(addedCards)) {
            // 如果以 + 结尾的数据
            String endWithPlusLine = "";
            long endWithPlusLineRowNumber = 0L;
            String endWithPlusLineCardName = "";
            for (RawDataLine rawDataLine : addedCards) {
                String line = rawDataLine.getLine();
                long rowNumber = rawDataLine.getRowNumber();
                String cardName = CardUtils.getCardName(rawDataLine.getLine());
                if (StringUtils.isNotBlank(line) && line.trim().endsWith("+")) {
                    endWithPlusLine = line;
                    endWithPlusLineRowNumber = rowNumber;
                    endWithPlusLineCardName = cardName;
                    continue;
                }
                IsfdMeshCompareResultFileVo add = new IsfdMeshCompareResultFileVo();
                add.setComparerResultType(IsfdMeshCompareResultTypeEnum.ADD.getDesc());
                if (StringUtils.isNotBlank(line) && line.trim().startsWith("+")) {
                    line = endWithPlusLine + line;
                    rowNumber = endWithPlusLineRowNumber;
                    cardName = endWithPlusLineCardName;
                }
                add.setCardName(cardName);
                add.setComparedContent(line);
                add.setComparedLine(rowNumber);
                add.setComparedFileName(rawDataLine.getRelativePath());
                addData.add(add);
            }
        }
        List<RawDataLine> removedCards = result.getRemovedCards();
        List<IsfdMeshCompareResultFileVo> removeData = new ArrayList<>();
        if (!CollectionUtils.isEmpty(removedCards)) {
            // 如果以 + 结尾的数据
            String endWithPlusLine = "";
            long endWithPlusLineRowNumber = 0L;
            String endWithPlusLineCardName = "";
            for (RawDataLine rawDataLine : removedCards) {
                String line = rawDataLine.getLine();
                long rowNumber = rawDataLine.getRowNumber();
                String cardName = CardUtils.getCardName(rawDataLine.getLine());
                if (StringUtils.isNotBlank(line) && line.trim().endsWith("+")) {
                    endWithPlusLine = line;
                    endWithPlusLineRowNumber = rowNumber;
                    endWithPlusLineCardName = cardName;
                    continue;
                }
                IsfdMeshCompareResultFileVo remove = new IsfdMeshCompareResultFileVo();
                remove.setComparerResultType(IsfdMeshCompareResultTypeEnum.REMOVE.getDesc());
                if (StringUtils.isNotBlank(line) && line.trim().startsWith("+")) {
                    line = endWithPlusLine + line;
                    rowNumber = endWithPlusLineRowNumber;
                    cardName = endWithPlusLineCardName;
                }
                remove.setCardName(cardName);
                remove.setReferencedContent(line);
                remove.setReferencedLine(rowNumber);
                remove.setReferencedFileName(rawDataLine.getRelativePath());
                removeData.add(remove);
            }
        }
        List<BDFCompareResult.ModifiedCard> modifiedCards = result.getModifiedCards();
        List<IsfdMeshCompareResultFileVo> modifiedData = new ArrayList<>();
        if (!CollectionUtils.isEmpty(modifiedCards)) {
            for (BDFCompareResult.ModifiedCard modifiedCard : modifiedCards) {
                List<RawDataLine> oldRawDataLines = modifiedCard.getOldRawDataLine();
                List<RawDataLine> newRawDataLines = modifiedCard.getNewRawDataLine();
                int maxSize = Math.max(oldRawDataLines.size(), newRawDataLines.size());
                for (int i = 0; i < maxSize; i++) {
                    IsfdMeshCompareResultFileVo modified = new IsfdMeshCompareResultFileVo();
                    modified.setComparerResultType(IsfdMeshCompareResultTypeEnum.MODIFIED.getDesc());
                    RawDataLine oldLine = i < oldRawDataLines.size() ? oldRawDataLines.get(i) : null;
                    RawDataLine newLine = i < newRawDataLines.size() ? newRawDataLines.get(i) : null;
                    if (oldLine != null) {
                        if (StringUtils.isBlank(modified.getCardName())) {
                            modified.setCardName(CardUtils.getCardName(oldLine.getLine()));
                        }
                        modified.setComparedContent(oldLine.getLine());
                        modified.setComparedLine((long) oldLine.getRowNumber());
                        modified.setComparedFileName(oldLine.getRelativePath());
                    }
                    if (newLine != null) {
                        if (StringUtils.isBlank(modified.getCardName())) {
                            modified.setCardName(CardUtils.getCardName(newLine.getLine()));
                        }
                        modified.setReferencedContent(newLine.getLine());
                        modified.setReferencedLine((long) newLine.getRowNumber());
                        modified.setReferencedFileName(newLine.getRelativePath());
                    }
                    modifiedData.add(modified);
                }
            }
        }

        Map<String, Object> data = new HashMap<>();
        data.put(IsfdMeshCompareResultTypeEnum.ADD.getDesc(), addData);
        data.put(IsfdMeshCompareResultTypeEnum.REMOVE.getDesc(), removeData);
        data.put(IsfdMeshCompareResultTypeEnum.MODIFIED.getDesc(), modifiedData);

        String prefixPath = iSysDictDataService.selectDictValueByTypeAndLabel(IsfdMeshModelConstants.MODEL_MESH, IsfdMeshModelConstants.MODEL_MESH_DATA_PREFIX);
        if (StringUtils.isBlank(prefixPath)) {
            throw new BaseException("自然网格模型库上传地址前缀未配置，请到字典菜单栏配置该项。");
        }

        String compareResultFileUrl = prefixPath + IsfdMeshModelConstants.MODEL_MESH_DATA_COMPARE_DIR + isfdMeshCompareResult.get_id() + ".xlsx";
        ExcelUtil.writeDataToExcel(data, IsfdMeshCompareResultFileVo.class, compareResultFileUrl);
        isfdMeshCompareResult.setCompareResultFileUrl(compareResultFileUrl);
    }
}
